<?php
/**
 * Created by PhpStorm.
 * User: cnpscy
 * Date: 2020/7/6
 * Time: 22:07
 * Note: BaseModel.php
 */

namespace App\Model;

use EasySwoole\EasySwoole\Config;
use EasySwoole\EasySwoole\EasySwooleEvent;
use EasySwoole\ORM\AbstractModel;

class BaseModel extends AbstractModel
{
    public $primaryKey = 'id';//主键
    // 都是非必选的，默认值看文档下面说明
    protected $autoTimeStamp = false;
    protected $createTime    = 'created_time';
    protected $updateTime    = 'updated_time';

    /** @var string 连接池名称 */
    protected $connectionName = 'default';

    public $is_delete    = 1;//是否删除
    public $delete_field = 'is_delete';//删除字段

    public $withModel = [],//关联模型
        $detailWithModel = [];//详情的模型

    // 单例
    protected static $instance;

    // 默认的数据表名
    protected $_tableName;

    const MONTH_SUB_TABLE = false; // 开启月分表


    public static $insert = false;
    public static $update = false;
    public static $delete = false;


    public function __construct(array $data = [])
    {
        parent::__construct($data);

        $this->__autoload($this);
    }

    public static function create(array $data = []): AbstractModel
    {
        $model = self::__autoload(new static);
        return $model->data($data);
    }

    /**
     * 模型初始化以及调用静态方法时，需要自动加载的方法
     *
     * @param $model
     *
     * @return mixed
     */
    protected static function __autoload($model)
    {
        $model = $model->setTableName($model);
        if ($model instanceof MonthTable) {
            $model->setMonthTable('', $model);
        }
        $model = $model->base($model);
        return $model;
    }

    /**
     * 自动设置表名
     *
     * @param $model
     *
     * @return mixed
     */
    protected function setTableName($model)
    {
        if (empty($model->tableName)) {
            // 数据表前缀
            $prefix = Config::getInstance()->getConf('Mysql.' . $model->connectionName . '.prefix');

            // 数据表名 按照模型转化成 下划线+小写
            $model_fie_name = explode('\\', get_called_class());
            $tableName      = $prefix . strtolower(string_underscore_lowercase(end($model_fie_name))); // 如果表名存在大写，那么自动转换成：下划线+小写

            // 设置数据表名必须为复数
            $model->tableName = get_string_pluralize($tableName); // 复数
        }
        if (empty($model->_tableName)) $model->_tableName = $model->tableName;
        return $model;
    }

    /**
     * 自动加载删除条件
     *
     * @param $model
     *
     * @return mixed
     */
    protected function base($model)
    {
        if (intval($model->is_delete) == 0 && !empty($model->delete_field)) $model->where($model->delete_field, 0);
        return $model;
    }

    /**
     * 单例
     *
     * @param mixed ...$args
     *
     * @return \App\Model\BaseModel
     */
    static function getInstance(...$args)
    {
        if (!isset(self::$instance)) {
            self::$instance = new static(...$args);
        }
        return self::$instance;
    }

    /**
     * 分页
     *
     * @param int $limit
     * @param int $page
     *
     * @return array
     * @throws \EasySwoole\ORM\Exception\Exception
     * @throws \Throwable
     */
    public function paginate($params = []): array
    {
        if (!isset($params['page'])) $params['page'] = 1;
        if (!isset($params['limit'])) $params['limit'] = 10;

        $model = $this->page((int)$params['page'], (int)$params['limit'])->withTotalCount(); //获取数据

        $data = $model->all();

        //获取查询结果对象
        $lastResult = $model->lastQueryResult();

        //获取查询数据总数,查询时需要调用`withTotalCount`才可以使用该方法
        $count = $lastResult->getTotalCount();

        return [
            'total'        => $count,                        //总数量
            'current_page' => $params['page'],                         //当前页面
            'page_size'    => $params['limit'],                        //每页数量
            'total_page'   => intval(ceil($count / $params['limit'])), //总页码
            'data'         => $data,                         //数据
        ];
    }

    public function updateBatch($tableName, $multipleData = [], string $id = 'id')
    {
        // 写库
        $this->connectionName = EasySwooleEvent::setMysqlConnection('write');

        try {
            if (empty($multipleData)) {
                throw new \Exception("数据不能为空");
            }
            $firstRow = current($multipleData);

            $updateColumn = array_keys($firstRow);
            // 默认以id为条件更新，如果没有ID则以第一个字段为条件
            $referenceColumn = isset($firstRow[$id]) ? $id : current($updateColumn);
            unset($updateColumn[0]);
            // 拼接sql语句
            $updateSql = "UPDATE " . $tableName . " SET ";
            $sets      = [];
            $bindings  = [];
            foreach ($updateColumn as $uColumn) {
                $setSql = "`" . $uColumn . "` = CASE ";
                foreach ($multipleData as $data) {
                    $setSql     .= "WHEN `" . $referenceColumn . "` = ? THEN ? ";
                    $bindings[] = $data[$referenceColumn];
                    $bindings[] = $data[$uColumn];
                }
                $setSql .= "ELSE `" . $uColumn . "` END ";
                $sets[] = $setSql;
            }
            $updateSql .= implode(', ', $sets);
            $whereIn   = collect($multipleData)->pluck($referenceColumn)->values()->all();
            $bindings  = array_merge($bindings, $whereIn);
            $whereIn   = rtrim(str_repeat('?,', count($whereIn)), ',');
            $updateSql = rtrim($updateSql, ", ") . " WHERE `" . $referenceColumn . "` IN (" . $whereIn . ")";
            // 传入预处理sql语句和对应绑定数据
            return DB::update($updateSql, $bindings);
        } catch (\Exception $e) {
            return false;
        }
    }

    /**
     * 获取主键
     *
     * @return string
     * @throws \EasySwoole\ORM\Exception\Exception
     */
    public function getPrimaryKey(): string
    {
        if (isset($this->primaryKey) && !empty($this->primaryKey)) return $this->primaryKey;
        return $this->schemaInfo()->getPkFiledName();
    }

    public function getInfoByWhere($where, $fileds = '*')
    {
        return $this->where($where)->field($fileds)->get();
    }

    public function getInfoById($id, $fileds = '*')
    {
        return $this->where($this->getPrimaryKey(), $id)->field($fileds)->get();
    }


    /**
     *
     * 系统底层自带的方法：写的全部方法，设置为：‘写’的数据库连接配置
     *
     */

    public function save()
    {
        $this->connection('write', true);
        return parent::save(); // TODO: Change the autogenerated stub
    }

    public function destroy($where = null, $allow = false)
    {
        $this->connection('write', true);
        return parent::destroy($where, $allow); // TODO: Change the autogenerated stub
    }

    public function saveAll($data, $replace = true, $transaction = true)
    {
        $this->connection('write', true);
        return parent::saveAll($data, $replace, $transaction); // TODO: Change the autogenerated stub
    }

    public function update(array $data = [], $where = null, $allow = false)
    {
        $this->connection('write', true);
        return parent::update($data, $where, $allow); // TODO: Change the autogenerated stub
    }

    protected static function onBeforeInsert($model)
    {

    }

    protected static function onAfterInsert($model, $res)
    {

    }

    protected static function onBeforeUpdate($model)
    {

    }

    protected static function onAfterUpdate($model, $res)
    {

    }

    protected static function onBeforeDelete($model)
    {

    }

    public static function onAfterDelete($model, $res)
    {

    }
}